# 通过列表生成式，我们可以直接创建一个列表。但是，受到内存限制，列表容量肯定是有限的。而且，
# 创建一个包含100万个元素的列表，
# 从而节省大量的空间。在Python中，这种一边循环一边计算的机制，称为生成器：generator。
# 要创建一个generator，有很多种方法。第一种方法很简单，只要把一个列表生成式的[]改成()，就创建了一个generator：
L = [x*x for x in range(11)]
print(L)

g=(x*x for x in range(11))
#打印的是生成器生成的list的地址
print(g)
print(next(g),next(g))

#next(g)实在是太变态了，正确的方法是使用for循环，因为generator也是可迭代对象：
l1=[1,2,3]
l2=[9,10,11]
g=(x+n for x in l1 for n in l2)
for v in g:
    print(v)
#斐波拉契数列（Fibonacci），除第一个和第二个数外，任意一个数都可由前两个数相加得到：
def fib(max):
    n,a,b=0,0,1
    while n< max:
        print(b)
        a,b=b,a+b#t = (b, a + b) # t是一个tuple,a = t[0] b = t[1]

        n=n+1
    return  'done'
fib(5)
print("****************************************************************")

# 函数定义中包含yield关键字，那么这个函数就不再是一个普通函数，而是一个ge
# nerator函数，调用一个generator函数将返回一个generator：

def fib1(max):
    n,a,b=0,0,1
    while n< max:
        yield b
        a,b=b,a+b#t = (b, a + b) # t是一个tuple,a = t[0] b = t[1]
        n=n+1
    return  'done'
f=fib1(5)
print("生成器函数返回一个生成器:",f)
for v in f:
    print(v)
print("*********************生成器返回顺序*******************************************")
#普通函数是顺序执行，遇到return语句或者最后一行函数语句就返回。而变成generator的函数，
# 在每次调用next()的时候执行，遇到yield语句返回，再次执行时从上次返回的yield语句处继续执行
def testdo():
    print('step1')
    yield 1
    print('step 2')
    yield 3
    print('step3')
    yield 5
#调用该generator函数时，首先要生成一个generator对象，然后用next()函数不断获得下一个返回值：
o=testdo()
for i in o:
    print(i)
#for循环调用generator时，发现拿不到generator的return语句的返回值。
# 如果想要拿到返回值，必须捕获StopIteration错误，返回值包含在StopIteration的value中：
g=fib1(7)
while True:
    try:
        x=next(g)
        print('g=',str(x))
    except StopIteration as  e:
        print('自定义生成器函数最后的return：',e.value)
        break

